home *** CD-ROM | disk | FTP | other *** search
- /* This XAD client is written by Kyzer/CSG <kyzer@4u.net>, the actual
- * decompression code is written by bzip2's author, Julian Seward. bzip2
- * is (C) 1996-2000 Julian R. Seward. Please see some of his files for more
- * information.
- *
- * License:
- * - The modified and unmodified files of libbzip2 are (C) Julian R. Seward
- * and retain their original license. However, you should not directly
- * use these modified versions, you should obtain the original bzip2
- * and libbzip2 from http://sourceware.cygnus.com/bzip2/
- * - This slave and its source code is licensed to Dirk Stoecker for
- * inclusion in his XAD distribution without further conditions.
- * - For all other people, this slave is licensed under the GNU General
- * public license, version 2.
- *
- * Although this slave should work perfectly with an unmodifed libbzip2
- * compiled with BZ_NO_STDIO, I have made changes:
- * - all compression-related code is removed. It is unneccessary in a
- * decompression-only slave.
- * - all high level functionality in bzlib.c is removed, leaving only
- * low-level decompression code - bzDecompress(Init|%|End)
- * - the decompresser has been modified to try and enter 'small mode' if
- * it cannot allocate enough memory for 'fast mode'.
- * - 'assertion failures' are turned into error codes, as this slave can't
- * support the immediate exit() that libbzip2 would like.
- * - the random number table rNums has been made into Int16 instead of Int32
- */
-
- /* bzip2 is actually just a file compressor, and doesn't even include any
- * details about the file itself - perhaps this should be an XFD slave
- * instead? A couple of reasons why not:
- *
- * 1. tar files are archives. gzip'ed tar files are archives too. 99% of
- * bzip2 compressed files are tar archives. therefore, if gzip is an xad
- * slave, bzip2 is an xad slave too.
- *
- * 2. bzip2 takes astonishing amounts of memory to unpack - it's far more a
- * UNIX archive compressor than it is a realtime depacker for demos and
- * games, which is the ethos of XFD compressors.
- */
-
- /* bzip2 file format:
- * - first, the header: 'BZh1' to 'BZh9'
- * - the 1-9 in the header is the size of a block / 100000
- *
- * - next, 0 or more compressed data blocks
- * - the block starts with recogdata: $314159265359 (BCD pi :)
- * - then comes a 4 byte CRC-so-far
- * - then the various state tables
- * - then the sorted randomized huffed RLE data
- *
- * - a final block containing no data is always included
- * - it's recog is $177245385090, however after the first block
- * the data is 87.5% likely not to be byte aligned, so you probably
- * won't see it in a hex editor.
- * - there's a 4 byte final CRC, but for the reason mentioned above,
- * it's difficult to check.
- *
- * - minimum size of file is 14 bytes for a 0 byte input file (just a
- * header and the final block, no data blocks), or 37 bytes for a 1 byte
- * input file
- *
- * bzip2, by virtue of early recklessness and backwards compatibility on
- * the part of the author, does not contain *any* information whatsoever
- * about the data itself, it can't even know how long a block is without
- * decompressing it. But hey! It beats gzip on compression, so that's got
- * to be good, right?
- */
-
- /* $VER: bzip2.c 1.2 (19.05.00) */
-
- #include <exec/memory.h>
- #include <string.h>
-
- #include <libraries/xadmaster.h>
- #include <proto/xadmaster.h>
-
- #include "bzlib.h"
-
- #include "SDI_compiler.h"
- #define XADBASE REG(a6, struct xadMasterBase *xadMasterBase)
-
- #ifdef DEBUG
- void KPrintF(char *fmt, ...);
- #define D(x) x
- #define BG KPrintF
- #else
- #define D(x)
- #define BG
- #endif
-
-
- #ifndef XADMASTERFILE
- #define bzip2_Client FirstClient
- #define NEXTCLIENT 0
- const UBYTE version[] = "$VER: bzip2 1.2 (19.05.00)";
- #endif
- #define BZIP2_VERSION 1
- #define BZIP2_REVISION 0
-
-
- /*--- memory functions -----------------------------------------------------*/
-
- struct xadMasterBase *xadBase;
-
- struct mh {
- struct mh *next;
- };
-
- struct mh *initmem(XADBASE) {
- struct mh *base = (struct mh *) xadAllocVec(sizeof(struct mh), 0);
- xadBase = xadMasterBase;
- if (base) base->next = NULL;
- return base;
- }
-
- APTR allocmem(struct mh *base, ULONG size, ULONG flags) {
- struct xadMasterBase *xadMasterBase = xadBase;
- struct mh *mem = (struct mh *) xadAllocVec(size + sizeof(struct mh), flags);
- if (!mem) return NULL;
- mem->next = base->next; /* link into list */
- base->next = mem;
- return (APTR) ++mem;
- }
-
- void freemem(struct mh *base, APTR mem) {
- struct xadMasterBase *xadMasterBase = xadBase;
- struct mh *m, *x, *o;
-
- if (!mem || !base) return;
- m = (struct mh *) mem; m--; /* get correct address */
-
- for (o = base; (x = o->next); o = x) {
- if (x == m) {
- o->next = x->next;
- xadFreeObjectA((APTR)x, NULL);
- return;
- }
- }
- }
-
- void freeallmem(struct mh *base) {
- struct xadMasterBase *xadMasterBase = xadBase;
- while (base) {
- struct mh *next = base->next;
- xadFreeObjectA((APTR)base, NULL);
- base = next;
- }
- }
-
-
- /*--- xad slave -------------------------------------------------------------*/
-
- ASM(BOOL) bzip2_RecogData(REG(d0, ULONG size), REG(a0, STRPTR data), XADBASE) {
-
- /* check file header */
- if (data[0] != 'B' || data[1] != 'Z' || data[2] != 'h') return 0;
- if (data[3] < '1' || data[3] > '9') return 0;
-
- /* check first block header */
-
- if (data[4] == 0x31) {
- if (data[5] != 0x41 || data[6] != 0x59) return 0;
- if (data[7] != 0x26 || data[8] != 0x53 || data[9] != 0x59) return 0;
- }
- else {
- if (data[4] != 0x17 || data[5] != 0x72 || data[6] != 0x45) return 0;
- if (data[7] != 0x38 || data[8] != 0x50 || data[9] != 0x90) return 0;
- }
-
- /* we're happy with it */
- return 1;
- }
-
-
- ASM(LONG) bzip2_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- struct TagItem datetags[] = {
- { XAD_DATECURRENTTIME, 1 },
- { XAD_GETDATEXADDATE, 0 },
- { TAG_DONE, 0 }
- };
-
- /* there's only one file in a bzip archive - the uncompressed data */
- struct xadFileInfo *fi;
-
- fi = (struct xadFileInfo *) xadAllocObjectA(XADOBJ_FILEINFO, NULL);
- if (!(ai->xai_FileInfo = fi)) return XADERR_NOMEMORY;
-
- fi->xfi_Flags = XADFIF_NODATE | XADFIF_NOUNCRUNCHSIZE
- | XADFIF_NOFILENAME | XADFIF_SEEKDATAPOS;
- fi->xfi_EntryNumber = 1;
- fi->xfi_FileName = xadMasterBase->xmb_DefaultName;
- fi->xfi_CrunchSize = ai->xai_InSize - 14;
- fi->xfi_Size = 0;
- fi->xfi_DataPos = 0;
-
- /* fill in today's date */
- datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
- xadConvertDatesA(datetags);
-
- return XADERR_OK;
- }
-
-
- /* bz2lib support functions */
- void bz_internal_error() { }
- void *bzalloc(void *base, int a, int b) {
- return allocmem((struct mh *)base, a*b, 0);
- }
- void bzfree(void *base, void *mem) {
- freemem((struct mh *)base, mem);
- }
-
-
- ASM(LONG) bzip2_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- struct mh *base;
- char *buf_in, *buf_out;
- const int bufsize = 8192;
- int size;
- bz_stream bzs;
- LONG err, bzerr;
-
- /* ensure we're decrunching our only file! */
- if (!ai || !ai->xai_CurFile || ai->xai_CurFile->xfi_EntryNumber != 1)
- return XADERR_BADPARAMS;
-
- /* initialise memory system */
- ai->xai_PrivateClient = (APTR) (base = initmem(xadMasterBase));
- bzs.opaque = base;
- bzs.bzalloc = bzalloc;
- bzs.bzfree = bzfree;
-
- /* allocate some buffers */
- buf_in = allocmem(base, bufsize, MEMF_PUBLIC);
- buf_out = allocmem(base, bufsize, MEMF_PUBLIC);
- if (!buf_in || !buf_out) return XADERR_NOMEMORY;
-
- /* force immediate read-in of data on first run only */
- bzs.avail_in = 0;
-
- /* always keep going - exit is only when demand passes EOF */
- while (1) {
- /* initialise the decompression state */
- if ((bzerr=BZ2_bzDecompressInit(&bzs, 0, 0)) != BZ_OK)
- return XADERR_NOMEMORY;
-
- /* reset output buffer */
- bzs.avail_out = bufsize;
- bzs.next_out = buf_out;
-
- while (bzerr == BZ_OK) {
- /* fill input buffer when empty */
- if (bzs.avail_in == 0) {
- size = ai->xai_InSize - ai->xai_InPos;
- if (size > bufsize) size = bufsize;
- if (size == 0) return XADERR_OK; /** normal exit point = EOF **/
- if((err = xadHookAccess(XADAC_READ, size, buf_in, ai))) return err;
- bzs.next_in = buf_in;
- bzs.avail_in = size;
- }
-
- /* do some more decompression */
- bzerr = BZ2_bzDecompress(&bzs);
-
- /* purge any output */
- if ((size = bufsize - bzs.avail_out) > 0) {
- if((err = xadHookAccess(XADAC_WRITE, size, buf_out, ai))) return err;
- bzs.next_out = buf_out;
- bzs.avail_out = bufsize;
- }
- }
-
- switch (bzerr) {
- case BZ_STREAM_END: BZ2_bzDecompressEnd(&bzs); break;
- case BZ_DATA_ERROR:
- case BZ_DATA_ERROR_MAGIC: return XADERR_ILLEGALDATA;
- case BZ_MEM_ERROR: return XADERR_NOMEMORY;
- default: return XADERR_DECRUNCH;
- }
- }
- return XADERR_DECRUNCH; /* not reached! */
- }
-
-
- ASM(void) bzip2_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
- freeallmem((struct mh *) ai->xai_PrivateClient);
- ai->xai_PrivateClient = NULL;
- }
-
-
- const struct xadClient bzip2_Client = {
- NEXTCLIENT, XADCLIENT_VERSION, 6, BZIP2_VERSION, BZIP2_REVISION,
-
- 14, /* minimum archive size */
- XADCF_FILEARCHIVER | XADCF_FREEFILEINFO, /* type of client and flags */
- 0, /* internal ID (not needed) */
- "BZip2", /* name of client */
-
- /* client functions */
- (BOOL (*)()) bzip2_RecogData,
- (LONG (*)()) bzip2_GetInfo,
- (LONG (*)()) bzip2_UnArchive,
- (void (*)()) bzip2_Free
- };
-